/*
* erpc_dual_test.c
*
*  Created on: Nov 14, 2020
*      Author: guyadong
*/
#include <string.h>
#include <signal.h>
#include <iostream>
#include <time.h>
#include <cassert>
#include <stddef.h>
#include <common_utilits.h>
#include <file_utilits.h>
#include <cmdline.h>
#include <erpc_threading.h>
#include <erpc_client_setup.h>
#include <erpc_setup_dual_serial.h>
#include <erpc_server_setup.h>
#include <erpcdemo_server.h>

#ifndef BINARY_OUTPUT_SIZE
// used by erpc_list_cast.hpp,for output binary
#define BINARY_OUTPUT_SIZE 256
#endif /** BINARY_OUTPUT_SIZE */
using namespace std;
using namespace gdface;
using namespace erpc;
namespace gdface {
	// dual serial transport 测试程序运行参数
	class ErpcDualConfig {
	public:
		const int PROXY_DEFAULT_BAUD_RATE = 115200;
		const std::string PARAM_PORT_NAME = "portName";
		const std::string PARAM_BAUD_RATE = "baudRate";
		const std::string PARAM_FLAG = "flag";
		cmdline::parser cmdparam;
		std::string portName;
		int baudRate;
		int flag;
		inline ErpcDualConfig()
		: cmdparam()
		, portName()
		, baudRate(PROXY_DEFAULT_BAUD_RATE)
		, flag(3) {
			cmdparam.add<std::string>(PARAM_PORT_NAME, 'p', "serial port name,such as '/dev/ttyS0','/dev/ttyUSB1'", true);
			cmdparam.add<int>(PARAM_BAUD_RATE, 'b', "serial baud rate", false, PROXY_DEFAULT_BAUD_RATE, cmdline::range(1, 65535));
			cmdparam.add<int>(PARAM_FLAG, 'f', "run flag,1:only client,2:only server,3:both", false, 3, cmdline::range(1, 3));
		}
		inline void parse(int argc, char*argv[]) {
			auto program_name = get_file_name(argv[0]);
			cmdparam.set_program_name(program_name);
			cmdparam.parse_check(argc, argv);
			afterParse();
		}
		virtual ~ErpcDualConfig()=default;
	protected:
		inline virtual void afterParse() {
			portName = cmdparam.get<std::string>(PARAM_PORT_NAME);
			baudRate = cmdparam.get<int>(PARAM_BAUD_RATE);
			flag = cmdparam.get<int>(PARAM_FLAG);
		}
	};
} /* namespace gdface */
#ifdef binary_t_DEFINED
std::ostream&
operator<<(std::ostream& out, const binary_t& obj)
{
  if (obj.data) {
    if (BINARY_OUTPUT_SIZE > 32 && obj.dataLength > BINARY_OUTPUT_SIZE) {
      out << ::gdface::com_utilits::bytes_to_hex_string(obj.data, 16);
      out << "...size:" << obj.dataLength << "...";
      out << ::gdface::com_utilits::bytes_to_hex_string(obj.data + obj.dataLength - 16, 16);
    }
    else {
      out << ::gdface::com_utilits::bytes_to_hex_string(obj.data, (size_t)obj.dataLength);
    }
  }else{
    out << "<null>";
  }
  return out;
}
#endif /** binary_t_DEFINED */

static void now_time_str (char *buffer,size_t size)
{
	time_t rawtime;
	struct tm * timeinfo;
	time (&rawtime);
	timeinfo = localtime (&rawtime);
	strftime (buffer,size,"%Y/%m/%d %H:%M:%S",timeinfo);
 }

/* eRPC server thread */
static Thread serverThread([](void *arg){
	erpc_server_run(); /* or erpc_server_poll(); */
});

/*
 * 销毁服务端,客户端及传输层对象
 */
static void deinit(void)
{
  	erpc_client_deinit();
  	erpc_server_deinit();
  	/* 关闭传输层 */
    erpc_transport_dual_serial_deinit();
}

static void stop(int signo)
{
    printf("User break,destroy serial transport\n");
  	deinit();
    ::exit(0);
}
int main(int argc, char *argv[])
{
	ErpcDualConfig param;
	param.parse(argc, argv);
	std::cout <<"======connect serial port:" << param.portName <<  " baud rate:" << param.baudRate << std::endl;

	/* 初始化传输层对象(serial) */
	erpc_status_t status = erpc_transport_dual_serial_init(param.portName.c_str(), param.baudRate);
	if(status)
	{
		std::cout << "erpc_transport_dual_serial_init error:" << status << std::endl;
		::exit(-1);
	}
	/** 服务端传输层对象 */
	auto server_transport = erpc_transport_dual_serial_get(true);
	/** 客户端传输层对象 */
	auto client_transport = erpc_transport_dual_serial_get(false);
	/* MessageBufferFactory initialization */
	auto message_buffer_factory = erpc_mbf_dynamic_init();
	/* 初始化客户端 */
	erpc_client_init(client_transport, message_buffer_factory);
	/* eRPC server side initialization */
	erpc_server_init(server_transport, message_buffer_factory);
	/* connect generated service into server, look into erpcdemo_server.h */
  	erpc_add_service_to_server(create_DEMO_service());

  	signal(SIGINT, stop);
  	if(param.flag & 2)
  	{
		printf("====start DEMO server\n");
		if(param.flag & 1){
			/* 异步方式启动服务 */
			serverThread.start(nullptr);
		}else{
			/* 同步方式启动服务 */
			erpc_server_run(); /* or erpc_server_poll(); */
		}
  	}
  	if(param.flag & 1)
  	{
  		printf("====start loop client call\n");
  		while(true)
  		{
  			/* RPC 调用 RD_demoHello */
  			binary_t _return;
  			char time_str[64];
  			now_time_str(time_str,sizeof(time_str));
  			char hello_str[128];
  			snprintf(hello_str,128,"%s,%s","hello,service",time_str);
  			auto resp = RD_demoHello(&_return,hello_str);
  			std::cout << "CLIENT:return code:" << resp << std::endl;
  			if(resp){
  				std::cout << "CLIENT:error :" << resp << std::endl;
  			}else{
  				/* 输出返回值 */
  				std::cout << "CLIENT:RD_demoHello response:" << _return << std::endl;
  			}
  			Thread::sleep(4*1000*1000);
  		}
  	}
  	deinit();
}
